<!--
  * 消息推送
  *
  * @Author:    chenyuqiang
  * @Date:      2025-09-06 23:11:23
  * @Copyright  1
-->
<template>
  <a-modal
      :title="form.id ? '编辑消息模板' : '新增消息模板'"
      :width="800"
      :open="visibleFlag"
      @cancel="onClose"
      :maskClosable="false"
      :destroyOnClose="true"
  >
    <a-form ref="formRef" :model="form" :rules="rules" :label-col="{ span: 4 }" :wrapper-col="{ span: 19 }">
      <a-row>
        <a-col :span="12">
          <a-form-item label="标题" name="title">
            <a-input v-model:value="form.title" placeholder="请输入标题" />
          </a-form-item>
        </a-col>
      </a-row>

      <a-row :gutter="16">
        <a-col :span="12">
          <a-form-item label="名称" name="name">
            <a-input v-model:value="form.name" placeholder="请输入模板名称" />
          </a-form-item>
        </a-col>
        <a-col :span="12">
          <a-form-item label="状态" name="socStatus">
            <DictSelect v-model:value="form.socStatus" dict-code="wxstatus" placeholder="请选择状态"/>
          </a-form-item>
        </a-col>
      </a-row>

      <a-form-item label="规则" name="epl">
        <div class="epl-editor">
          <a-textarea
            ref="eplInputRef"
            v-model:value="form.epl"
            :rows="4"
            placeholder="请输入规则"
            @focus="handleEplFocus"
            @input="handleEplInput"
            @keydown.enter.prevent="handleEnterKey"
            @keydown.up.prevent="handleUpKey"
            @keydown.down.prevent="handleDownKey"
            @keydown.tab.prevent="handleTabKey"
          />
          <div
            v-if="showSuggestions && filteredSuggestions.length > 0"
            class="suggestions-dropdown"
            :style="suggestionStyle"
          >
            <div
              v-for="(item, index) in filteredSuggestions"
              :key="index"
              class="suggestion-item"
              :class="{ active: currentSuggestionIndex === index }"
              @click="handleSuggestionSelect(item)"
              @mouseenter="currentSuggestionIndex = index"
            >
              <span class="suggestion-label">{{ item.label }}</span>
              <span class="suggestion-type">{{ item.type === 'field' ? '字段' : '运算符' }}</span>
            </div>
          </div>
        </div>
      </a-form-item>

      <a-form-item label="消息模板" name="smsTemp">
        <a-textarea v-model:value="form.smsTemp" :rows="4" placeholder="请输入消息模板内容" />
      </a-form-item>

      <a-form-item label="微信地址" name="wxsign">
        <a-input v-model:value="form.wxsign" placeholder="请输入微信地址" />
      </a-form-item>
    </a-form>

    <template #footer>
      <a-space>
        <a-button @click="onClose">取消</a-button>
        <a-button type="primary" @click="onSubmit" :loading="loading">保存</a-button>
      </a-space>
    </template>
  </a-modal>
</template>
<script setup>
import { reactive, ref, nextTick, computed, onMounted, onUnmounted } from 'vue';
import _ from 'lodash';
import { message } from 'ant-design-vue';
import { SmartLoading } from '/@/components/framework/smart-loading';
import { wxsmApi } from '/@/api/business/wxsm/wxsm-api';
import { smartSentry } from '/@/lib/smart-sentry';
import DictSelect from '/@/components/support/dict-select/index.vue';
import { fieldConfigApi } from '/@/api/business/elasticsearch/field-config-api';

// ------------------------ 事件 ------------------------

const emits = defineEmits(['reloadList']);
const loading = ref(false);

// ------------------------ EPL编辑器相关 ------------------------
const eplInputRef = ref(null);
const showSuggestions = ref(false);
const currentSuggestionIndex = ref(0);
const suggestionStyle = ref({
  top: '0px',
  left: '0px'
});

// 字段配置选项
const fieldOptions = ref([]);

// 获取字段配置
const getFieldConfig = async () => {
  try {
    SmartLoading.show();
    const response = await fieldConfigApi.getFieldList();
    if (response.data) {
      fieldOptions.value = Object.values(response.data).map(item => ({
        label: `${item.displayName}(${item.entityName})`,
        value: item.entityName,
        type: 'field'
      }));
    }
  } catch (error) {
    smartSentry.captureError(error);
    message.error('获取字段配置失败');
  } finally {
    SmartLoading.hide();
  }
};

// EPL输入上下文
const eplInputContext = reactive({
  text: '',
  startPos: 0,
  endPos: 0,
  type: 'field', // 'field' | 'operator' | 'value' | 'relation'
  expectingValue: false // 是否正在等待输入值
});

// 运算符列表
const operators = [
  { label: '==', value: '==', type: 'operator' },
  { label: '!=', value: '!=', type: 'operator' },
  { label: '>', value: '>', type: 'operator' },
  { label: '<', value: '<', type: 'operator' },
  { label: '>=', value: '>=', type: 'operator' },
  { label: '<=', value: '<=', type: 'operator' },
  { label: 'contains', value: 'contains', type: 'operator' }
];

// 关系运算符
const relationOperators = [
  { label: 'and', value: 'and', type: 'relation' },
  { label: 'or', value: 'or', type: 'relation' }
];

// 处理EPL输入框获得焦点
const handleEplFocus = async () => {
  if (!fieldOptions.value?.length) {
    await getFieldConfig();
  }
  // 不自动显示下拉框，只加载字段配置
  eplInputContext.type = 'field';
};

// 处理EPL输入
const handleEplInput = (e) => {
  const textarea = e.target;
  const cursorPosition = textarea.selectionStart;
  const textBeforeCursor = textarea.value.substring(0, cursorPosition);
  const words = textBeforeCursor.split(/\s+/);
  const currentWord = words[words.length - 1] || '';
  const previousWord = words[words.length - 2];

  // 根据上下文决定当前应该提示什么
  if (eplInputContext.expectingValue) {
    // 如果正在等待输入值，显示匹配的建议
    const searchText = currentWord.toLowerCase();
    const matchingValues = fieldOptions.value
      .filter(field => field.value.toLowerCase().includes(searchText))
      .map(field => ({ value: field.value, label: field.label, type: 'value' }));
    
    if (matchingValues.length > 0) {
      eplInputContext.text = searchText;
      showSuggestions.value = true;
    } else {
      showSuggestions.value = false;
    }
    
    // 如果输入了完整的值，切换到关系运算符模式
    if (currentWord.trim().length > 0 && !currentWord.includes(' ')) {
      eplInputContext.expectingValue = false;
      eplInputContext.type = 'relation';
    }
  } else if (operators.some(op => op.value === previousWord)) {
    // 如果前一个词是运算符，期待输入值
    eplInputContext.expectingValue = true;
    eplInputContext.type = 'value';
    showSuggestions.value = false;
  } else if (currentWord.length > 0 && !currentWord.includes('"')) {
    // 如果当前有输入且不是在输入值，显示建议
    eplInputContext.text = currentWord;
    showSuggestions.value = true;

    // 根据上下文决定显示什么类型的建议
    if (words.length >= 2 && words[words.length - 2].includes('"')) {
      eplInputContext.type = 'relation';
    } else if (words.length >= 2 && operators.some(op => op.value === words[words.length - 2])) {
      eplInputContext.type = 'value';
    } else if (words.length >= 2 && relationOperators.some(op => op.value === words[words.length - 2])) {
      eplInputContext.type = 'field';
    } else {
      eplInputContext.type = 'field';
    }
  }

  nextTick(() => {
    const { top, left } = getCaretCoordinates(textarea, cursorPosition);
    suggestionStyle.value = {
      top: `${top + 20}px`,
      left: `${left}px`
    };
  });
};

// 处理建议项选择
const handleSuggestionSelect = (suggestion) => {
    // 立即关闭当前下拉框
    showSuggestions.value = false;

    // 获取当前光标位置和文本
    const textarea = eplInputRef.value.$el;
    const cursorPosition = textarea.selectionStart;
    const fullText = form.epl || '';
    const textBeforeCursor = fullText.substring(0, cursorPosition);
    const textAfterCursor = fullText.substring(cursorPosition);

    // 找到最后一个空格的位置，用于定位当前输入的词
    const lastSpaceIndex = textBeforeCursor.lastIndexOf(' ');
    const currentInputStart = lastSpaceIndex === -1 ? 0 : lastSpaceIndex + 1;
    
    // 获取当前词之前的所有内容
    const baseText = textBeforeCursor.substring(0, currentInputStart);
    
    // 如果是运算符模式，需要保留之前选择的字段
    const currentWord = textBeforeCursor.substring(currentInputStart).trim();
    const previousContent = eplInputContext.type === 'operator' ? textBeforeCursor.substring(0, cursorPosition) : baseText;

    // 将选中的值写入到规则输入框中
    if (eplInputContext.type === 'field') {
      // 如果是字段，替换当前输入的文本
      form.epl = baseText + suggestion.value + textAfterCursor;
      eplInputContext.type = 'operator';
    } else if (eplInputContext.type === 'operator') {
      // 如果是运算符，保留之前的字段并添加运算符
      form.epl = previousContent + ' ' + suggestion.value + ' ' + textAfterCursor;
      eplInputContext.expectingValue = true;
      eplInputContext.type = 'value';
    } else if (eplInputContext.type === 'relation') {
      // 如果是关系运算符，添加空格
      form.epl = baseText + suggestion.value + ' ' + textAfterCursor;
      eplInputContext.type = 'field';
    }

    // 更新光标位置
    nextTick(() => {
      let newPosition;
      if (eplInputContext.type === 'operator') {
        // 如果是运算符，光标位置应该在运算符和空格之后
        newPosition = previousContent.length + suggestion.value.length + 2;
      } else {
        // 其他情况下的光标位置计算
        newPosition = baseText.length + suggestion.value.length + (eplInputContext.type === 'value' ? 0 : 1);
      }
      textarea.setSelectionRange(newPosition, newPosition);
    });

  nextTick(() => {
    // 如果选择的是字段，切换到运算符模式
    if (suggestion.type === 'field') {
      eplInputContext.type = 'operator';
      eplInputContext.text = '';
      // 使用setTimeout确保在DOM更新后再显示下拉
      setTimeout(() => {
        showSuggestions.value = true;
      }, 100);
    } else {
      // 如果选择的是运算符，切换回字段模式
      eplInputContext.type = 'field';
      eplInputContext.text = '';
    }
  });
};


// 获取过滤后的建议列表
const filteredSuggestions = computed(() => {
  const searchText = eplInputContext.text.toLowerCase();
  
  if (eplInputContext.type === 'operator') {
    return operators.filter(op => 
      !searchText || op.value.toLowerCase().includes(searchText)
    );
  }

  if (eplInputContext.type === 'relation') {
    return relationOperators.filter(op =>
      !searchText || op.value.toLowerCase().includes(searchText)
    );
  }

  if (eplInputContext.type === 'value' || eplInputContext.expectingValue) {
    // 值输入时提供字段值作为建议，不添加引号
    return fieldOptions.value
      .filter(field => !searchText || field.value.toLowerCase().includes(searchText))
      .map(field => ({ value: field.value, label: field.label, type: 'value' }));
  }

  // 字段匹配
  return fieldOptions.value.filter(field => {
    // 优先精确匹配开头
    if (field.value.toLowerCase().startsWith(searchText) || 
        field.label.toLowerCase().startsWith(searchText)) {
      return true;
    }
    // 其次包含匹配
    return field.value.toLowerCase().includes(searchText) || 
           field.label.toLowerCase().includes(searchText);
  }).sort((a, b) => {
    const aStartsWithValue = a.value.toLowerCase().startsWith(searchText);
    const bStartsWithValue = b.value.toLowerCase().startsWith(searchText);
    const aStartsWithLabel = a.label.toLowerCase().startsWith(searchText);
    const bStartsWithLabel = b.label.toLowerCase().startsWith(searchText);
    
    // 优先级：值开头匹配 > 标签开头匹配 > 值包含匹配 > 标签包含匹配
    if (aStartsWithValue !== bStartsWithValue) return bStartsWithValue - aStartsWithValue;
    if (aStartsWithLabel !== bStartsWithLabel) return bStartsWithLabel - aStartsWithLabel;
    return 0;
  });
});

// 处理回车键
const handleEnterKey = () => {
  if (showSuggestions.value && filteredSuggestions.value.length > 0) {
    handleSuggestionSelect(filteredSuggestions.value[currentSuggestionIndex.value]);
  }
};

// 处理向上键
const handleUpKey = () => {
  if (showSuggestions.value && filteredSuggestions.value.length > 0) {
    currentSuggestionIndex.value = (currentSuggestionIndex.value - 1 + filteredSuggestions.value.length) % filteredSuggestions.value.length;
  }
};

// 处理向下键
const handleDownKey = () => {
  if (showSuggestions.value && filteredSuggestions.value.length > 0) {
    currentSuggestionIndex.value = (currentSuggestionIndex.value + 1) % filteredSuggestions.value.length;
  }
};

// 处理Tab键
const handleTabKey = () => {
  if (showSuggestions.value && filteredSuggestions.value.length > 0) {
    handleSuggestionSelect(filteredSuggestions.value[currentSuggestionIndex.value]);
  }
};

// 点击外部关闭建议框
const handleClickOutside = (e) => {
  const target = e.target;
  // 如果点击的是输入框或者下拉列表中的选项，不关闭
  if (eplInputRef.value?.$el.contains(target) || 
      target.closest('.suggestions-dropdown') ||
      target.classList.contains('suggestion-item')) {
    return;
  }
  showSuggestions.value = false;
};

// 在组件挂载时添加事件监听
onMounted(() => {
  // 使用 mousedown 替代 click，因为 mousedown 在 focus 之前触发
  document.addEventListener('mousedown', handleClickOutside);
});

// 清理事件监听
onUnmounted(() => {
  document.removeEventListener('mousedown', handleClickOutside);
});

// ------------------------ 显示与隐藏 ------------------------
// 是否显示
const visibleFlag = ref(false);

async function show(rowData) {
  await getFieldConfig();
  Object.assign(form, formDefault);
  if (rowData && !_.isEmpty(rowData)) {
    Object.assign(form, rowData);
  }
  visibleFlag.value = true;
  nextTick(() => {
    formRef.value.clearValidate();
  });
}

function onClose() {
  Object.assign(form, formDefault);
  visibleFlag.value = false;
}

// ------------------------ 表单 ------------------------

// 组件ref
const formRef = ref();

const formDefault = {
  title: undefined, //标题
  name: undefined, //模板名称
  epl: undefined, //规则
  socStatus: undefined, //状态
  wxsign: undefined, //微信地址
  smsTemp: undefined, //消息模板
};

let form = reactive({ ...formDefault });

const rules = {
  title: [{ required: true, message: '请输入标题' }],
  name: [{ required: true, message: '请输入模板名称' }],
  epl: [{ required: true, message: '请输入规则' }],
  socStatus: [{ required: true, message: '请选择状态' }],
  wxsign: [{ required: true, message: '请输入微信地址' }],
  smsTemp: [{ required: true, message: '请输入消息模板内容' }],
};

// 点击确定，验证表单
async function onSubmit() {
  try {
    await formRef.value.validateFields();
    save();
  } catch (err) {
    message.error('请检查表单填写是否完整!');
  }
}

// 新建、编辑API
async function save() {
  loading.value = true;
  try {
    if (form.id) {
      await wxsmApi.update(form);
    } else {
      await wxsmApi.add(form);
    }
    message.success('保存成功');
    emits('reloadList');
    onClose();
  } catch (err) {
    smartSentry.captureError(err);
  } finally {
    loading.value = false;
  }
}

defineExpose({
  show,
});

// 获取光标坐标的辅助函数
function getCaretCoordinates(element, position) {
  const { offsetLeft, offsetTop } = element;
  const { lineHeight } = getComputedStyle(element);

  const div = document.createElement('div');
  div.style.cssText = getComputedStyle(element).cssText;
  div.style.height = 'auto';
  div.style.position = 'absolute';
  div.style.visibility = 'hidden';
  div.style.whiteSpace = 'pre-wrap';

  const textBeforeCursor = element.value.substring(0, position);
  div.textContent = textBeforeCursor;
  document.body.appendChild(div);

  const lines = Math.floor(div.offsetHeight / parseInt(lineHeight));
  const left = offsetLeft + (div.offsetWidth % element.offsetWidth);
  const top = offsetTop + (lines * parseInt(lineHeight));

  document.body.removeChild(div);

  return { top, left };
}
</script>

<style lang="less" scoped>
.epl-editor {
  position: relative;
  width: 100%;
  z-index: 1002;
}

.suggestions-dropdown {
  position: absolute;
  background: white;
  border: 1px solid #d9d9d9;
  border-radius: 4px;
  max-height: 200px;
  overflow-y: auto;
  z-index: 1000;
  box-shadow: 0 2px 8px rgba(0, 0, 0, 0.15);
}

.suggestion-item {
  padding: 8px 12px;
  cursor: pointer;
  display: flex;
  justify-content: space-between;
  align-items: center;
  
  &:hover, &.active {
    background: #e6f7ff;
  }

  .suggestion-label {
    color: rgba(0, 0, 0, 0.85);
  }

  .suggestion-type {
    font-size: 12px;
    color: rgba(0, 0, 0, 0.45);
    background: #f5f5f5;
    padding: 2px 6px;
    border-radius: 2px;
  }
}
</style>
